package com.bw.lib_avcore;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.util.Log;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @author ytx
 * @date 2025-10-23 10:48
 * @description 音视频编码
 */
public class MediaEncoder {
    private static final String TAG = "MediaEncoder";
    private Config mConfig; //配置
    private MediaEncoder(Config config){
        this.mConfig = config;
    }
    private volatile static MediaEncoder instance;
    public static MediaEncoder getInstance(Config config){
        if(instance == null){
            synchronized (MediaEncoder.class){
                if(instance == null){
                    instance = new MediaEncoder(config);
                }
            }
        }
        return instance;
    }


    private MediaCodec vEncoder;//视频编码器
    private MediaCodec aEncoder;//音频编码器

    private LinkedBlockingDeque<byte[]> videoQueue = new LinkedBlockingDeque<>(); //视频数据队列

    private Thread videoEncoderThread;//视频编码线程
    private boolean videoEncoderLoop;


    /**
     * 添加视频数据
     */
    public void putVideoData(byte[]  data){
        try {
            videoQueue.put(data);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 停止视频编码
     */
    public void stopVideoEncode(){
        videoEncoderLoop = false;
        if (videoEncoderThread != null){
            videoEncoderThread.interrupt();
        }
        if (vEncoder != null){
            vEncoder.stop();
        }
    }

    public void releaseVideoEncoder(){
        if (vEncoder != null){
            vEncoder.release();
            vEncoder = null;
        }

    }




    /**
     * 开始视频编码
     */
    public void startVideoEncode(){
        if (vEncoder == null){
            throw new RuntimeException("视频编码器未初始化");
        }
        videoEncoderThread = new Thread(new Runnable() {
            @Override
            public void run() {
                vEncoder.start();//启动编码器
                while (videoEncoderLoop && !Thread.currentThread().isInterrupted()){
                    try {
                        byte[] bytes = videoQueue.take(); //取出数据
                        //编码
                        encodeVideoData( bytes);

                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        videoEncoderLoop = true;
        videoEncoderThread.start();

    }
    private MediaCodec.BufferInfo vBufferInfo = new MediaCodec.BufferInfo();
    /**
     * 视频编码： 输入：喂数据   输出：拿编码后数据
     * @param data
     */
    public void encodeVideoData(byte[] data){
        ByteBuffer[] inputBuffers = vEncoder.getInputBuffers();
        ByteBuffer[] outputBuffers = vEncoder.getOutputBuffers();
        //喂数据
        int inputBufferIndex = vEncoder.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0){
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(data,0,data.length);
            vEncoder.queueInputBuffer(inputBufferIndex,0,data.length,0,0);//pts
        }
        //取数据：编码后的数据--->回调数据
        int outputBufferIndex = vEncoder.dequeueOutputBuffer(vBufferInfo, 0);
        if (outputBufferIndex >= 0){
            ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
            if (mCallback != null){
                mCallback.outputVideoData(outputBuffer,vBufferInfo);
            }
            vEncoder.releaseOutputBuffer(outputBufferIndex,false);
        }

    }

    /**
     * 初始化视频编码器
     */
    public void initVideoEncoder(int width,int height) throws IOException {
        //获得当前设备支持的编码器
        MediaCodecInfo mediaCodecInfo = getMediaCodecInfo(MediaFormat.MIMETYPE_VIDEO_AVC);
        //获得当前编码器支持的颜色格式：YUV420P
        int colorFormat = getColorFormat(mediaCodecInfo);

        //创建视频编码器
        MediaCodec mediaCodec = MediaCodec.createByCodecName(mediaCodecInfo.getName());
        //配置编码器的参数
        MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
        mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); //颜色格式
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, mConfig.bitRate); //码率
        mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,mConfig.fps); //帧率
        mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, mConfig.iFrameInternal); //关键帧间隔
        mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); //CONFIGURE_FLAG_ENCODE 编码器
        vEncoder = mediaCodec;
    }

    /**
     * 获得当前设备编码器支持的颜色格式
     * @param mediaCodecInfo
     * @return
     */
    public int getColorFormat(MediaCodecInfo mediaCodecInfo){
        int matchedForamt = 0;
        MediaCodecInfo.CodecCapabilities capabilitiesForType = mediaCodecInfo.getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_AVC);
        for (int i = 0; i < capabilitiesForType.colorFormats.length; i++){
            int colorFormat = capabilitiesForType.colorFormats[i];
            if (colorFormat >= MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar &&
                    colorFormat <= MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar
            ) {
                if (colorFormat >= matchedForamt) {
                    matchedForamt = colorFormat;
                    break;
                }
            }
        }
        switch (matchedForamt) {
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
                Log.i(TAG, "selected yuv420p");
                break;
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
                Log.i(TAG, "selected yuv420pp");
                break;
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
                Log.i(TAG, "selected yuv420sp");
                break;
            case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
                Log.i(TAG, "selected yuv420psp");
                break;
        }


            return matchedForamt;


    }

    /**
     * 当前设备是否支持h264编码
     * @param mimeType
     * @return
     */

    public MediaCodecInfo getMediaCodecInfo(String mimeType){
        int codecCount = MediaCodecList.getCodecCount();//获得当前设备支持个数
        for (int i = 0 ;i < codecCount;i++){
            MediaCodecInfo mediaCodecInfo = MediaCodecList.getCodecInfoAt(i);
            if (!mediaCodecInfo.isEncoder()){
                continue;
            }
            String[] types = mediaCodecInfo.getSupportedTypes(); //获得支持的编码类型
            for (String type : types){
                if (type.equalsIgnoreCase(mimeType)){
                    return mediaCodecInfo;
                }
            }
        }
        return null;
    }

    private Callback mCallback;

    /**
     * 设置回调
     *
     * @param callback 回调
     */
    public void setCallback(Callback callback) {
        this.mCallback = callback;
    }


    public interface Callback {
        void outputVideoData(ByteBuffer bb, MediaCodec.BufferInfo info);

        void outputAudioData(ByteBuffer bb, MediaCodec.BufferInfo info);
    }


}
